# -*- coding: utf-8 -*-

import math
import os
import functools
from ModuleOne import *  #使用from ModuleOne import *这种方式import，可以直接调用该类的公开方法  如果只是import class的话，需要class.方法来调用
import  ModuleOne
from functools import reduce
from operator import itemgetter


# def quadratic(a, b, c):
#     denta = math.pow(b, 2) - 4 * a * c
#     if denta > 0:
#         hah = math.sqrt(denta)
#         x1 = (-b + hah) / (2 * a)
#         x2 = (-b - hah) / (2 * a)
#         return x1, x2
#
# print('quadratic(2, 3, 1) =', quadratic(2, 3, 1))
# print('quadratic(1, 3, -4) =', quadratic(1, 3, -4))
#
# def add_end(L = None):
#     if L is None:
#         L = []
#     L.append('END')
#     return L
#
# print(add_end())
# print(add_end())
#
# # 传递可变参数
# def calc(*numbers):
#     sum = 0
#     for n in numbers:
#         sum = sum + n * n
#     return sum
#
# # 函数参数为可变参数时，可传空
# print(calc())
# print(calc(2,3,5))
# list = [1,2,3]
# # 调用传递可变参数时，如果是变量，需在变量前加*号
# print(calc(*list))
# # 关键字参数 **参数名
# def person(name, age, **kw):
#     print('name:', name, 'age:', age, 'other:', kw)
#
# person('monkey', 8)
# person('monkey', 6, woca='nidaye')
# dict = {'city': 'Beijing', 'job': 'Engineer'}
# person('mokey', 90, **dict)
#
# def f1(a, b, c=0, *abc, **dict):
#     print(a, b, c, abc, dict)
# def f2(a, b, c=3, *, d, **kw):
#     print(a, b, c, d, kw)
#
# f1(1,2)
# f1(1,2,3)
# f1(1,2,3,'5','6')
# f1(1,2,3,5,6,abc='nidaye')
# f2(1,2,d=99,abc='python')
#
# args1 = (1, 2, 3, 4)
# kw1 = {'d': 99, 'x': '#'}
# f1(*args1, **kw1)
#
# args2 = (1, 2, 3)
# kw2 = {'d': 88, 'x': '#'}
# f2(*args2, **kw2)
#
# def cheng(*n):
#     a = 1;
#     for i in n:
#         a = i * a
#     return a
#
# print(cheng(1,2,3,4,5,6))
#
# # 递归函数  一个函数调用自己本身
# # def fact(n):
# #     if n == 1:
# #         return 1
# #     return n * fact(n-1)
#
# # 尾递归
# def fact(n):
#     return fact_iter(n, 1)
#
# def fact_iter(num, product):
#     if num == 1:
#         return product
#     return fact_iter(num - 1, num * product)
#
# print(fact(5))
#
# # 利用递归函数移动汉诺塔
# def move(n, a, b, c):
#     if n == 1:
#         print('move', a, '-->', c)
#     else:
#         move(n-1, a, c, b)
#         move(1, a, b, c)
#         move(n-1 ,b, a, c)
#
# move(5, 'a', 'b', 'c')
#
#
# L = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
# # 利用切片范围取值
# print(L[1:3]) # L[0:3]表示，从索引0开始取，直到索引3为止，但不包括索引3。即索引0，1，2，正好是3个元素。
# # 如果第一个索引是0，还可以省略：
# print(L[:3]) # L[:3]等价与L[0:3]
# # L[-1]取倒数第一个元素，那么它同样支持倒数切片
# print(L[-2:-1])

# R = list(range(100))
# # 从0开始取到第十位
# print('R[:10] =', R[:10])
# # 取倒数10位
# print('R[-10:] =', R[-10:])
# # 前11-20个数
# print('R[10:20] =', R[10:20])
# # 前10个数，每两个取一个：
# print('R[:10:2] =', R[:10:2])
# # 所有数，每5个取一个：
# print('R[::5] =', R[::5])

# 去除字符串中所有空格
# def trim(str):
#     a = ''
#     for s in str:
#         if not s.isspace():
#             a = a + s
#     return a
#
# print(trim('       hello   '))
#
# # 找最大值和最小值
# def findMinAndMax(L):
#     min = L[0]
#     max = L[0]
#     for a in L:
#         if min > a:
#             min = a
#         elif max < a:
#             max = a
#     return min, max
#
# print(findMinAndMax([1,2,3,4,5,6,7,8]))

# # 列表生成式
# print([x * x for x in range(1, 11)])
# # 列表生成式 只取偶数
# print([x * x for x in range(1, 11) if x % 2 == 0])
#
# print([x + y for x in 'ABC' for y in 'XYZ'])
# print([d for d in os.listdir('.')])
#
# d = {'x': 'A', 'y': 'B', 'z': 'C' }
# # 利用列表生成式 遍历字典并生成列表
# print([x + '=' + y for x , y in d.items()])
#
# L1 = ['Hello', 'World', 18, 'Apple', None]
# # 利用列表生成式 ，把字符串全部变成小写，加判断是否是字符串，避免报错
# print([s.lower() for s in L1 if isinstance(s, str)])

# def new_abs(n):
#     if n < 0:
#         return -n
#     else:
#         return n
# # 高阶函数 :函数可以作为参数，在函数中传递
# f = new_abs  # 变量f指向new_abs, f即是一个等同于new_abs的一个函数
# def add(x, y, f): # 将f当作add函数的参数进行传递，即为最为简单的一种高阶函数
#     return f(x) + f(y)
#
# print(add(-4, -5, f))

# 高阶函数map(函数，Iterable（可迭代对象）)
# def f(x):
#     return x * x;
# a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
# L = map(f, a)
# print(list(L))
# # 高阶函数reduce  必须接收两个参数，reduce把结果继续和序列的下一个元素做累积计算
# def add(x, y):
#     return x + y
# sum = reduce(add, a)
# print(sum)

# def fn(x, y):
#     return x * 10 + y
#
# def char2num(s):
#     digits = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
#     return digits[s]
# num = reduce(fn, map(char2num, '13579'))
# print(num)

# 结果同上
# DIGITS = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
#
# def str2int(s):
#     def fn(x, y):
#         return x * 10 + y
#     def char2num(s):
#         return DIGITS[s]
#     return reduce(fn, map(char2num, s))
#
# print(str2int('13579'))
#
# def prod(x, y):
#     return x * y
# print(reduce(prod, [3, 5, 7, 9]))

# CHAR_TO_FLOAT = {
#     '0': 0,
#     '1': 1,
#     '2': 2,
#     '3': 3,
#     '4': 4,
#     '5': 5,
#     '6': 6,
#     '7': 7,
#     '8': 8,
#     '9': 9,
#     '.': -1
# }
#
# def str2float(s):
#     nums = map(lambda ch: CHAR_TO_FLOAT[ch], s)
#     point = 0
#     def to_float(f, n):
#         nonlocal point
#         if n == -1:
#             point = 1
#             return f
#         if point == 0:
#             return f * 10 + n
#         else:
#             point = point * 10
#             return f + n / point
#     return reduce(to_float, nums, 0.0)
#
# print(str2float('0'))
# print(str2float('123.456'))
# print(str2float('123.45600'))
# print(str2float('0.1234'))
# print(str2float('.1234'))
# print(str2float('120.0034'))

# def normalize(name):
#     # capitalize()把字符串第一个字母转化为大写字母，其余小写;  title() 把单词的第一个字符转为大写，其余小写
#     return name.capitalize()
#
# print(list(map(normalize, ['adam', 'LISA', 'barT'])))
#
# # filter和map()类似，也接收一个函数和一个序列。和map()不同的是，filter()把传入的函数依次作用于每个元素，然后根据返回值是True还是False决定保留还是丢弃该元素。
# # 例如，在一个list中，删掉偶数，只保留偶数，可以这么写：
# def is_odd(s):
#     return s % 2 == 0
#
# print(list(filter(is_odd, [1,2,3,4,5,6,7,8,9])))
# # 把一个序列中的空字符串删掉，可以这么写：
# def not_empty(s):
#     return s and s.strip()
# print(list(filter(not_empty, ['A', '', 'B', None, 'C', '  '])))

# def main():
#     for n in primes():
#         if n < 1000:
#             print(n)
#         else:
#             break
#
# def _odd_iter():
#     n = 1
#     while True:
#         n = n + 2
#         yield n
#
# def _not_divisible(n):
#     return lambda x: x % n > 0
#
# def primes():
#     yield 2
#     it = _odd_iter()
#     while True:
#         n = next(it)
#         yield n
#         it = filter(_not_divisible(n), it)
#
# if __name__ == '__main__':
#     main()

# # 排序 sorted
# print(sorted([36, 5, -12, 9, -21]))
# # sorted()函数也是一个高阶函数，它还可以接收一个key函数来实现自定义的排序，例如按绝对值大小排序
# print(sorted([36, 5, -12, 9, -21], key=abs))
# # 我们给sorted传入key函数，即可实现忽略大小写的排序：
# print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower))
# # 反向排序，不必改动key函数，可以传入第三个参数reverse=True：
# print(sorted(['bob', 'about', 'Zoo', 'Credit'], key=str.lower, reverse=True))
#
#
# students = [('Bob', 75), ('Adam', 92), ('Bart', 66), ('Lisa', 88)]
#
# # 按名字排序
# print(sorted(students, key=itemgetter(0)))
# # 再按成绩从低到高排序：
# print(sorted(students, key=lambda t: t[1]))
# # 再按成绩从高到低排序：
# print(sorted(students, key=itemgetter(1), reverse=True))

# 返回函数  把函数sum()作为返回参数
# def lazy_sum(*args):
#     def sum():
#         ax = 0
#         for n in args:
#             ax = ax + n
#         return ax
#     return sum
#
# f = lazy_sum(1,2,3,4,5,6)
# print(f())
#
# # 返回函数数组  把装有f(j)函数的数组作为参数返回
# def count():
#     def f(j):
#         def g():
#             return j * j
#         return g
#     lists = []
#     for n in range(1, 4):
#         lists.append(f(n))
#     return lists
#
# f1, f2, f3 = count()
# print(f1(), f2(), f3())
#
# # 匿名函数:  lambda 参数(a): 表达式(a % 2 == 1)  不需要定义函数名,表达式只能有一句,不用写return
# L = list(filter(lambda a : a % 2 == 1, range(1, 20)))
# print(L)

# 函数对象有一个__name__属性，可以拿到函数的名字
# def now():
#     print('hellopython')
#
# print(now.__name__)
# 装饰器(decorator) : 在代码运行期间动态增加功能的方式
# def log(func):
#     def wapper(*args, **kw):
#         print('call %s() :' % func.__name__)
#         return func(*args, **kw)
#     return wapper
#
# # 观察上面的log，因为它是一个decorator，所以接受一个函数作为参数，并返回一个函数。我们要借助Python的@语法，把decorator置于函数的定义处：
# @log # 把@log放到now()函数的定义处，相当于执行了语句：now = log(now)
# def now():
#     print('hellopython')
#
# now()
# print(now.__name__)
# now()函数名经过装饰器后，函数名已经变为wapper，可经过以下修改，保证函数名不会变化:
# def log(func):
#     @functools.wraps(func)
#     def wrapper(*args, **kw):
#         print('call %s():' % (func.__name__))
#         return func(*args, **kw)
#     return wrapper
#
# @log
# def now():
#     print('hellopython')
#
# now()
# print(now.__name__) # 装饰器内部通过 @functools.wraps(func) 方法，可以保证函数名不会被改变
#
# # functools.partial 创建一个偏函数, base参数，默认值为10。如果传入base参数(2,8,16)，就可以做N进制的转换：
# int2 = functools.partial(int, base = 10)
# print(int2('8'))

# 调用ModuleOne模块的方法 只能调用公开的方法，private方法不可调用
public_func('from ModuleOne import *导入   方法调用')
ModuleOne.public_func('import  ModuleOne 导入   方法调用')